package bsf.system.configparser;

/**
 * Created by chejiangyi on 2017/3/30.
 */

import bsf.base.BsfException;
import bsf.system.cache.SimpleLruCache;
import bsf.util.ConvertUtil;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置字符串解析
 * 备注:使用时建议使用静态字典或者全局单例模式,便于使用缓存效果。
 */
public class ConfigStringParser<T>{
    private static final char INFO_SPILT_CHAR = ';';
    private static final char KEYVALUE_SPILT_CHAR = '=';
    private static final HashMap<String, String> KEY_REPLACE_CHARS = new HashMap();
    private static final HashMap<String, String> VALUE_REPLACE_CHARS = new HashMap();
    private static final HashMap<String, String> VALUE_Temp_REPLACE_CHARS = new HashMap();
    private SimpleLruCache<String, T> cache = new SimpleLruCache<String, T>(20);

    static {
        //Key中的空格去除,.=>_
        KEY_REPLACE_CHARS.put(" ", "");
        KEY_REPLACE_CHARS.put(".", "_");
        //连接字符串中的特殊字符= [=],; [;] 的转义支持
        VALUE_Temp_REPLACE_CHARS.put("[=]", "[&1]");
        VALUE_Temp_REPLACE_CHARS.put("[;]", "[&2]");
        VALUE_REPLACE_CHARS.put("[&1]", "=");
        VALUE_REPLACE_CHARS.put("[&2]", ";");


    }


    private String ReplaceStr(String str, HashMap<String, String> replace) {
        for (Map.Entry<String, String> r : replace.entrySet()) {
            str = str.replace(r.getKey(), r.getValue());
        }
        return str;
    }


    /**
     * 根据字符串信息解析配置信息
     * 配置规范:属性=值;属性=值
     * 备注:属性可以忽略大小写,值不得包含=或;这类敏感字符,
     *
     * @param stringinfo
     * @return
     */
    public final T Parse(String stringinfo,Class<T> cls) {
        try {
            T value = cache.get(stringinfo);
            if (value != null) {
                return value;
            } else {
                value = ParseString(stringinfo,cls);
                value = cache.set(stringinfo, value);
                return value;
            }
        } catch (Exception exp) {
            throw new BsfException("配置字符串解析失败" + exp.getMessage(), this.getClass());
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Field p : this.getClass().getDeclaredFields()) {
            if (Modifier.isPublic(p.getModifiers())) {
                String value = "";
                try {
                    value = (p.get(this) == null ? "" : p.get(this).toString());
                } catch (Exception exp) {
                }
                value = ReplaceStr(ReplaceStr(value, VALUE_REPLACE_CHARS), VALUE_Temp_REPLACE_CHARS);
                sb.append(p.getName() + KEYVALUE_SPILT_CHAR + value + INFO_SPILT_CHAR);
            }

        }
        return StringUtils.strip(sb.toString(), INFO_SPILT_CHAR + "");
    }

    private T ParseString(String stringinfo,Class<T> cls) {
        stringinfo = ReplaceStr(stringinfo, VALUE_Temp_REPLACE_CHARS);
        String[] infos = StringUtils.split(StringUtils.strip(stringinfo, INFO_SPILT_CHAR + ""), INFO_SPILT_CHAR);
        HashMap<String, String> infosdic = new HashMap();
        //配置解析到字典
        for (String info : infos) {
            if (StringUtils.contains(info, KEYVALUE_SPILT_CHAR)) {
                try {
                    String[] keyandvalue = StringUtils.split(info, KEYVALUE_SPILT_CHAR);
                    if (keyandvalue.length != 2) {
                        continue;
                    }
                    String key = ReplaceStr(keyandvalue[0], KEY_REPLACE_CHARS).toLowerCase(); //忽略大小写,替换空格
                    String value = ReplaceStr(keyandvalue[1], VALUE_REPLACE_CHARS);
                    if (infosdic.containsKey(key)) {
                        value = infosdic.get(key);
                    } else {
                        infosdic.put(key, value);
                    }
                } catch (Exception exp) {
                    throw new BsfException("字符串解析失败,解析内容:" + info, this.getClass());
                }
            }
        }
        //配置信息转对象信息
        T t = null;
        try{t =(T)cls.newInstance();}catch (Exception exp){throw new BsfException("泛型类型T 必须实现无参构造函数");}
        for (Field p : t.getClass().getDeclaredFields()) {
            String name = p.getName().toLowerCase();
            if (infosdic.containsKey(name)) {
                try {
                    p.set(t, ConvertUtil.convert(infosdic.get(name), p.getType()));
                } catch (Exception exp) {
                    throw new BsfException("字符串解析失败,原因:类型转换失败,Key:" + name, this.getClass());
                }
            }
        }
        return t;
    }
}
